﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Transactions;
using SMA.GENTEv1.Dados;
using SMA.GENTEv1.Procedures;

namespace SMA.GENTEv1
{
    public class AcoesLegaisProcesso
    {
        #region Variaveis Membro
        private int _idProcesso;
        private Organizacao _organizacao;
        private string _numProcesso;
        private DateTime _dtAberturaProc;
        private DateTime? _dtFimProcesso;
        private string _obs;
        private List<AcoesLegaisReclamante> _reclamante;
        private List<AcoesLegaisHistoricoProcesso> _historico;
        private GENTEEntities _context;
        #endregion

        #region Parametros
        public int IdProcesso
        {
            get { return _idProcesso; }
            set { _idProcesso = value; }
        }

        public Organizacao Organizacao
        {
            get { return _organizacao; }
            set { _organizacao = value; }
        }

        public string NumProcesso
        {
            get { return _numProcesso; }
            set { _numProcesso = value; }
        }

        public DateTime DtAberturaProc
        {
            get { return _dtAberturaProc; }
            set { _dtAberturaProc = value; }
        }

        public DateTime? DtFimProcesso
        {
            get { return _dtFimProcesso; }
            set { _dtFimProcesso = value; }
        }

        public string Obs
        {
            get { return _obs; }
            set { _obs = value; }
        }

        public List<AcoesLegaisReclamante> Reclamante
        {
            get { return _reclamante; }
            set { _reclamante = value; }
        }

        public List<AcoesLegaisHistoricoProcesso> Historico
        {
            get { return _historico; }
            set { _historico = value; }
        }
        #endregion

        #region Construtores
        public AcoesLegaisProcesso()
        {
            _context = new GENTEEntities();
        }

        public AcoesLegaisProcesso(int _idprocesso, bool _carregaDados, bool _carregaReclamante, bool _carregaHistorico,
                                   bool _carregaOrganizacao)
        {
            _context = new GENTEEntities();
            if (!_carregaDados)
                this._idProcesso = _idprocesso;
            else
                Carregar(_idprocesso, _carregaReclamante, _carregaHistorico, _carregaOrganizacao);
        }
        #endregion

        #region Métodos Privados
        private static Expression<Func<TElement, bool>> BuildContainsExpression<TElement, TValue>(Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values)
        {
            if (null == valueSelector)
            {
                throw new
                    ArgumentNullException("valueSelector");
            }
            if (null == values) { throw new ArgumentNullException("values"); }

            ParameterExpression p = valueSelector.Parameters.Single();
            if (!values.Any())
            {
                return e => false;
            }

            var equals = values.Select(value =>
            (Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value,
            typeof(TValue))));
            var body = equals.Aggregate<Expression>((accumulate, equal) =>
            Expression.Or(accumulate, equal));
            return Expression.Lambda<Func<TElement, bool>>(body, p);
        }

        private void Carregar(int _idprocesso, bool _carregaReclamante, bool _carregaHistorico, bool _carregaOrganizacao)
        {
            try
            {
                var consulta = from processo in _context.tab_acoes_legais_processo
                               where processo.id_processo == _idprocesso
                               select new
                               {
                                   processo.id_processo,
                                   processo.tab_organizacao.Id_organizacao,
                                   processo.num_processo,
                                   processo.dt_abertura_proc,
                                   processo.dt_fim_processo,
                                   processo.obs
                               };

                var listConsulta = consulta.ToList();

                foreach (var list in listConsulta)
                {
                    this._idProcesso = list.id_processo;

                    if (_carregaOrganizacao)
                        this._organizacao = new Organizacao(list.Id_organizacao, false, false);
                    else
                    {
                        this._organizacao = new Organizacao();
                        this._organizacao.IdOrganizacao = list.Id_organizacao;
                    }
                    this._numProcesso = list.num_processo;
                    this._dtAberturaProc = list.dt_abertura_proc;
                    this._dtFimProcesso = list.dt_fim_processo;
                    this._obs = list.obs;

                    if (_carregaHistorico)
                    {
                        AcoesLegaisHistoricoProcesso historico = new AcoesLegaisHistoricoProcesso();
                        this._historico = historico.SelectHistorico(list.id_processo, false, false, false);
                    }

                    if (_carregaReclamante)
                    {
                        AcoesLegaisReclamante reclamante = new AcoesLegaisReclamante();
                        this._reclamante = reclamante.SelectReclamantes(list.id_processo, false, false);
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private int RetornaIdProcesso()
        {
            try
            {
                int _valorRetorno = 0;

                var consulta = (from processo in _context.tab_acoes_legais_processo
                                orderby processo.id_processo descending
                                select new
                                {
                                    processo.id_processo
                                }).Take(1);

                var listConsulta = consulta.ToList();

                foreach (var list in listConsulta)
                {
                    _valorRetorno = list.id_processo;
                }

                return _valorRetorno;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private int RetornaIdProcesso(string _numprocesso)
        {
            try
            {
                int _valorRetorno = 0;

                var consulta = (from processo in _context.tab_acoes_legais_processo
                                where processo.num_processo == _numprocesso
                                select new
                                {
                                    processo.id_processo
                                });

                var listConsulta = consulta.ToList();

                foreach (var list in listConsulta)
                {
                    _valorRetorno = list.id_processo;
                }

                return _valorRetorno;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private bool VerificaCadastro()
        {
            try
            {
                bool verifica = false;

                if (this._numProcesso == string.Empty)
                    throw new Exception("É necessário informa o número de processo!");

                if (this._idProcesso == 0)
                {
                    if (this._reclamante == null)
                        throw new Exception("É necessário informar ao menos um reclamante!");

                    if (this._reclamante.Count == 0)
                        throw new Exception("É necessário informar ao menos um reclamante!");

                    if (this._historico == null)
                        throw new Exception("É necessário informar o histórico do processo!");
                }

                if (this._reclamante != null)
                {
                    foreach (AcoesLegaisReclamante reclam in this._reclamante)
                    {
                        var consulta = (from reclamante in _context.tab_acoes_legais_reclamante
                                        where reclamante.tab_pessoa.Id_pessoa == reclam.PessoaReclamante.IdPessoa
                                        && reclamante.tab_acoes_legais_processo.num_processo == this._numProcesso
                                        select new
                                        {
                                            reclamante.id_reclamante_processo
                                        });

                        if (consulta.ToList().Count > 0)
                            throw new Exception("Um dos reclamantes selecionados já foram vinculados a este processo anteriormente. Operação cancelada!");
                    }
                }

                verifica = true;
                return verifica;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private bool VerificaNumProcesso()
        {
            try
            {
                bool verifica = true;

                var consulta = (from processo in _context.tab_acoes_legais_processo
                                where processo.num_processo == this._numProcesso
                                select new
                                {
                                    processo.id_processo,
                                    processo.dt_abertura_proc
                                });

                if (consulta.ToList().Count > 0)
                {
                    foreach (var list in consulta.ToList())
                    {
                        if (list.dt_abertura_proc != this._dtAberturaProc)
                            throw new Exception("Existe um processo com data de abertura diferente do que foi informado no cadastro. Favor verificar esta informação. Operação cancelada!");
                    }
                    verifica = false;
                }

                return verifica;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private bool VerificaFimProcesso(DateTime? _dtfimprocesso)
        {
            try
            {
                bool verifica = false;

                var consulta = (from processo in _context.tab_acoes_legais_processo
                                where processo.id_processo == this._idProcesso
                                select new
                                {
                                    processo.dt_abertura_proc
                                });

                var listConsulta = consulta.ToList();

                foreach (var list in listConsulta)
                {
                    if (_dtfimprocesso < list.dt_abertura_proc)
                        throw new Exception("A data de finalização deve ser maior que a data de abertura do processo. Operação cancelada!");
                }

                verifica = true;
                return verifica;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        #endregion

        #region Métodos Públicos
        public List<AcoesLegaisProcesso> SelectProcessoCombo(int _idorganizacao)
        {
            try
            {
                List<AcoesLegaisProcesso> listProcesso = new List<AcoesLegaisProcesso>();

                var consulta = (from processo in _context.tab_acoes_legais_processo
                                where processo.tab_organizacao.Id_organizacao == _idorganizacao
                                select new
                                {
                                    processo.id_processo,
                                    processo.num_processo
                                }).Distinct();

                var listConsulta = consulta.ToList();

                foreach (var list in listConsulta)
                {
                    AcoesLegaisProcesso processo = new AcoesLegaisProcesso();
                    processo.IdProcesso = list.id_processo;
                    processo.NumProcesso = list.num_processo;

                    listProcesso.Add(processo);
                }

                return listProcesso;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public List<AcoesLegaisProcesso> SelectProcesso(int _idorganizacao, int[] _processos, int[] _reclamantes, 
                                                        bool _carregaHistorico, bool _carregaReclamante)
        {
            try
            {
                List<AcoesLegaisProcesso> listProcesso = new List<AcoesLegaisProcesso>();

                var consulta = (from processo in _context.tab_acoes_legais_processo.Where((BuildContainsExpression<tab_acoes_legais_processo, int>(item => item.id_processo, _processos)))
                                where processo.tab_organizacao.Id_organizacao == _idorganizacao
                                select new
                                {
                                    processo.id_processo,
                                    processo.num_processo,
                                    processo.dt_abertura_proc,
                                    processo.dt_fim_processo,
                                    processo.obs
                                });

                var listConsulta = consulta.ToList();

                foreach (var list in listConsulta)
                {
                    AcoesLegaisProcesso processo = new AcoesLegaisProcesso();
                    processo.IdProcesso = list.id_processo;
                    processo.NumProcesso = list.num_processo;
                    processo.DtAberturaProc = list.dt_abertura_proc;
                    processo.DtFimProcesso = list.dt_fim_processo;
                    processo.Obs = list.obs;

                    if (_carregaHistorico)
                    {
                        AcoesLegaisHistoricoProcesso historico = new AcoesLegaisHistoricoProcesso();
                        processo.Historico = historico.SelectHistorico(list.id_processo, true, false, false);
                    }

                    if (_carregaReclamante)
                    {
                        AcoesLegaisReclamante reclamante = new AcoesLegaisReclamante();
                        processo.Reclamante = new List<AcoesLegaisReclamante>();
                        processo.Reclamante = reclamante.SelectReclamantes(_reclamantes, list.id_processo, false, true);
                    }

                    listProcesso.Add(processo);
                }

                return listProcesso;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public List<AcoesLegaisProcesso> SelectProcessoReclamante(int _idreclamante, bool _carregaHistorico, bool _carregaOrganizacao)
        {
            try
            {
                List<AcoesLegaisProcesso> listProcesso = new List<AcoesLegaisProcesso>();

                var consulta = from processo in _context.tab_acoes_legais_processo
                               join reclamante in _context.tab_acoes_legais_reclamante on processo.id_processo equals reclamante.tab_acoes_legais_processo.id_processo
                               where reclamante.id_reclamante_processo == _idreclamante 
                               select new
                               {
                                   processo.id_processo,
                                   processo.tab_organizacao.Id_organizacao,
                                   processo.num_processo,
                                   processo.dt_abertura_proc,
                                   processo.dt_fim_processo,
                                   processo.obs
                               };

                var listConsulta = consulta.ToList();

                foreach (var list in listConsulta)
                {
                    AcoesLegaisProcesso processo = new AcoesLegaisProcesso();
                    processo.IdProcesso = list.id_processo;
                    processo.NumProcesso = list.num_processo;
                    processo.DtAberturaProc = list.dt_abertura_proc;
                    processo.DtFimProcesso = list.dt_fim_processo;
                    processo.Obs = list.obs;

                    if (_carregaHistorico)
                    {
                        AcoesLegaisHistoricoProcesso historico = new AcoesLegaisHistoricoProcesso();
                        this._historico = historico.SelectHistorico(list.id_processo, false, false, false);
                    }

                    if (_carregaOrganizacao)
                        this._organizacao = new Organizacao(list.Id_organizacao, false, false);
                    else
                    {
                        this._organizacao = new Organizacao();
                        this._organizacao.IdOrganizacao = list.Id_organizacao;
                    }

                    listProcesso.Add(processo);
                }

                return listProcesso;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public List<AcoesLegaisProcesso> SelectProcesso(int _idprocesso)
        {
            try
            {
                List<AcoesLegaisProcesso> listProcesso = new List<AcoesLegaisProcesso>();

                var consulta = (from processo in _context.tab_acoes_legais_processo
                                where processo.id_processo == _idprocesso
                                select new
                                {
                                    processo.id_processo,
                                    processo.num_processo,
                                    processo.dt_abertura_proc,
                                    processo.dt_fim_processo,
                                    processo.obs
                                });

                var listConsulta = consulta.ToList();

                foreach (var list in listConsulta)
                {
                    AcoesLegaisProcesso processo = new AcoesLegaisProcesso();
                    processo.IdProcesso = list.id_processo;
                    processo.NumProcesso = list.num_processo;
                    processo.DtAberturaProc = list.dt_abertura_proc;
                    processo.DtFimProcesso = list.dt_fim_processo;
                    processo.Obs = list.obs;

                    listProcesso.Add(processo);
                }

                return listProcesso;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void Salvar()
        {
            using (TransactionScope scope = new TransactionScope())
            {
                try
                {
                    if (VerificaCadastro())
                    {
                        if (VerificaNumProcesso())
                        {
                            tab_acoes_legais_processo tabProcesso = new tab_acoes_legais_processo();
                            tabProcesso.tab_organizacaoReference.EntityKey = new System.Data.EntityKey("GENTEEntities.tab_organizacao", "Id_organizacao", this._organizacao.IdOrganizacao);
                            tabProcesso.num_processo = this._numProcesso;
                            tabProcesso.dt_abertura_proc = this._dtAberturaProc;
                            tabProcesso.dt_fim_processo = this._dtFimProcesso;
                            tabProcesso.obs = this._obs;

                            _context.AddTotab_acoes_legais_processo(tabProcesso);
                            _context.SaveChanges();

                            this._idProcesso = RetornaIdProcesso();

                            foreach (AcoesLegaisReclamante reclam in this._reclamante)
                            {
                                reclam.Processo = new List<AcoesLegaisProcesso>();
                                reclam.Processo.Add(this);
                                reclam.Salvar();

                                foreach (AcoesLegaisHistoricoProcesso hist in this._historico)
                                {
                                    hist.DtHoraCadastro = DateTime.Now;
                                    hist.PessoaCadastro = new Pessoa(7);
                                    hist.Salvar();

                                    if (hist.Imagem != null)
                                    {
                                        if (hist.Imagem.Path != string.Empty)
                                        {
                                            hist.Imagem.HistoricoProcesso = new AcoesLegaisHistoricoProcesso();
                                            hist.Imagem.HistoricoProcesso.IdHistoricoProcesso = hist.IdHistoricoProcesso;
                                            hist.Imagem.HistoricoProcesso.Processo = this;
                                            hist.Imagem.Descricao = "Imagem";
                                            hist.Imagem.Salvar();
                                        }
                                    }

                                    tab_acoes_reclamante_processo_historico_processo tabReclamanteHist = new tab_acoes_reclamante_processo_historico_processo();
                                    tabReclamanteHist.tab_acoes_legais_historico_processoReference.EntityKey = new System.Data.EntityKey("GENTEEntities.tab_acoes_legais_historico_processo", "id_historico_processo", hist.IdHistoricoProcesso);
                                    tabReclamanteHist.tab_acoes_legais_reclamanteReference.EntityKey = new System.Data.EntityKey("GENTEEntities.tab_acoes_legais_reclamante", "id_reclamante_processo", reclam.IdReclamanteProcesso);

                                    _context.AddTotab_acoes_reclamante_processo_historico_processo(tabReclamanteHist);
                                    _context.SaveChanges();
                                }
                            }
                        }
                        else
                        {

                            if (this._idProcesso == 0)
                                this._idProcesso = RetornaIdProcesso(this._numProcesso);

                            tab_acoes_legais_processo tabProcesso = (from processo in _context.tab_acoes_legais_processo
                                                                     where processo.id_processo == this._idProcesso
                                                                     select processo).First();

                            tabProcesso.tab_organizacaoReference.EntityKey = new System.Data.EntityKey("GENTEEntities.tab_organizacao", "Id_organizacao", this._organizacao.IdOrganizacao);
                            tabProcesso.num_processo = this._numProcesso;
                            tabProcesso.dt_abertura_proc = this._dtAberturaProc;
                            tabProcesso.dt_fim_processo = this._dtFimProcesso;
                            tabProcesso.obs = this._obs;

                            _context.SaveChanges();

                            foreach (AcoesLegaisReclamante reclam in this._reclamante)
                            {
                                reclam.Processo = new List<AcoesLegaisProcesso>();
                                reclam.Processo.Add(this);
                                reclam.Salvar();

                                foreach (AcoesLegaisHistoricoProcesso hist in this._historico)
                                {
                                    hist.DtHoraCadastro = DateTime.Now;
                                    hist.PessoaCadastro = new Pessoa(7);
                                    hist.Salvar();

                                    if (hist.Imagem != null)
                                    {
                                        if (hist.Imagem.Path != string.Empty)
                                        {
                                            hist.Imagem.HistoricoProcesso = new AcoesLegaisHistoricoProcesso();
                                            hist.Imagem.HistoricoProcesso.IdHistoricoProcesso = hist.IdHistoricoProcesso;
                                            hist.Imagem.HistoricoProcesso.Processo = this;
                                            hist.Imagem.Descricao = "Imagem";
                                            hist.Imagem.Salvar();
                                        }
                                    }

                                    tab_acoes_reclamante_processo_historico_processo tabReclamanteHist = new tab_acoes_reclamante_processo_historico_processo();
                                    tabReclamanteHist.tab_acoes_legais_historico_processoReference.EntityKey = new System.Data.EntityKey("GENTEEntities.tab_acoes_legais_historico_processo", "id_historico_processo", hist.IdHistoricoProcesso);
                                    tabReclamanteHist.tab_acoes_legais_reclamanteReference.EntityKey = new System.Data.EntityKey("GENTEEntities.tab_acoes_legais_reclamante", "id_reclamante_processo", reclam.IdReclamanteProcesso);

                                    _context.AddTotab_acoes_reclamante_processo_historico_processo(tabReclamanteHist);
                                    _context.SaveChanges();
                                }
                            }
                        }
                    }

                    scope.Complete();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }

            Procedure storeProc = new Procedure();
            storeProc.SPAberturaAcoesJudiciais(_context.Connection, this._idProcesso);
        }

        public void Excluir()
        {
            using (TransactionScope scope = new TransactionScope())
            {
                try
                {
                    AcoesLegaisImagemProcesso imagem = new AcoesLegaisImagemProcesso();
                    imagem.Excluir(this._idProcesso);

                    var consultaimg = (from tabreclamantehistorico in _context.tab_acoes_reclamante_processo_historico_processo
                                       join tabreclamante in _context.tab_acoes_legais_reclamante on tabreclamantehistorico.tab_acoes_legais_reclamante.id_reclamante_processo equals tabreclamante.id_reclamante_processo
                                       where tabreclamante.tab_acoes_legais_processo.id_processo == this._idProcesso
                                       select tabreclamantehistorico);

                    var listConsultaImg = consultaimg.ToList();

                    int[] idhistoricos = new int[listConsultaImg.Count];
                    int i = 0;
                    foreach (var list in listConsultaImg)
                    {
                        if (!idhistoricos.Contains(list.tab_acoes_legais_historico_processo.id_historico_processo))
                        {
                            idhistoricos[i] = list.tab_acoes_legais_historico_processo.id_historico_processo;
                            i++;
                        }

                        _context.DeleteObject(list);
                        _context.SaveChanges();
                    }

                    AcoesLegaisHistoricoProcesso historico = new AcoesLegaisHistoricoProcesso();
                    historico.Excluir(idhistoricos);

                    AcoesLegaisReclamante reclamante = new AcoesLegaisReclamante();
                    reclamante.Excluir(this._idProcesso);

                    var consultaproc = (from tabprocesso in _context.tab_acoes_legais_processo
                                        where tabprocesso.id_processo == this._idProcesso
                                        select tabprocesso);

                    var listConsultaProc = consultaproc.ToList();

                    foreach (var list in listConsultaProc)
                    {
                        _context.DeleteObject(list);
                        _context.SaveChanges();
                    }

                    scope.Complete();
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        public void FinalizarProcesso(DateTime? _dtfimprocesso)
        {
            try
            {
                if (VerificaFimProcesso(_dtfimprocesso))
                {
                    tab_acoes_legais_processo tabProcesso = (from processo in _context.tab_acoes_legais_processo
                                                             where processo.id_processo == this._idProcesso
                                                             select processo).First();

                    tabProcesso.dt_fim_processo = _dtfimprocesso;

                    _context.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        #endregion
    }
}
